﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimpleTCP;
using System.Threading.Tasks;
using System.Configuration;
using MsgEntity;
using CommonLib;
using System.IO;
using System.Runtime.InteropServices;
using System.Collections;
using System.Reflection;

namespace CommunicationLib
{   
    public class Communicator
    {
        public delegate void connectCallBack(
            IntPtr data,
            
            int len
            );

        public static event ApiCallBack CallBack;

        protected static void OnMessageCallBack (ApiCallBackEventArgs param)
        {
            if (CallBack != null)
            {
                CallBack(param);
            }
        }
        public delegate void messageCallBack(int code, string message);

        [DllImport("Keys-windows.dll")]
        public static extern int CInit_Env();

        [DllImport("Keys-windows.dll")]
        public static extern int CCreate_client_socket(connectCallBack back,string ip,int port);

        [DllImport("Keys-windows.dll")]
        public static extern int CSend_message(byte[] data, int len);

        [DllImport("Keys-windows.dll")]
        public static extern int CInit_message_callback(messageCallBack back);

        [DllImport("Keys-windows.dll")]
        public static extern int getSocketStatus();

        [DllImport("Keys-windows.dll")]
        public static extern void CClose_socket();

        [DllImport("Keys-windows.dll")]
        public static extern int CFinal_Env();

        [DllImport("Keys-windows.dll")]
        public static extern int CSign_dataEx_MD5(IntPtr sourcedata, int sourceLen,  IntPtr targetdata,
            ref int targetdataLen);

        connectCallBack _callBackDelegate = new connectCallBack(ConnectCallBack);

        public messageCallBack MsgCallBackDelegate = new messageCallBack(MessageCallBack);

        private static void MessageCallBack(int code, string message)
        {
            string bb = code.ToString("x6");
            string aa = message;
        }

        private static void ConnectCallBack(IntPtr data, int len)
        {
            if (len > 0)
            {
                byte[] ys = new byte[len];
                Marshal.Copy(data, ys, 0, len);
                ApiCallBackEventArgs param = new ApiCallBackEventArgs(ys, len);
                OnMessageCallBack(param);
            }
        }


        protected static bool Connected
        {
            get;
            set;
        }

        protected static int SendCount
        {
            get;
            set;
        }

        public bool ServerConnect(string addr,int port)
        {
            try
            {
                if (!Connected)
                {
                    int e = CInit_Env();
                    if (Equals(e,0) && CCreate_client_socket(_callBackDelegate, addr, port) > 0)
                    {
                        Connected = true;
                        SendCount = 1;                       
                        return true;
                    }
                    else
                    {
                        throw new Exception("连接失败！");
                    }
                }
                else
                {
                    throw new Exception("已经存在一个连接！");
                }
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }       

        public bool ServerDisconnect()
        {
            try
            {
                if (Connected)
                {
                    CClose_socket();
                    CFinal_Env();
                    Connected = false;
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return false;
        }

        /// <summary>
        /// 合并字节
        /// </summary>
        /// <param name="datalist"></param>
        /// <returns></returns>
        protected byte[] MergeData(List<byte[]> datalist)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                for (int i=0;i<datalist.Count ;i++)
                {
                    ms.Write(datalist[i], 0, datalist[i].Length);
                }
                return ms.ToArray();
            }
        }

        protected string GetSignature(byte[] rawData)
        {
            byte[] rawDataCopy = new byte[rawData.Length];
            rawData.CopyTo(rawDataCopy, 0);
            IntPtr targetdata = new IntPtr();
            int targetdataLen = 0;

            GCHandle hObject = GCHandle.Alloc(rawData, GCHandleType.Pinned);
            IntPtr sorucedata = hObject.AddrOfPinnedObject();

            int res = CSign_dataEx_MD5(sorucedata, rawData.Length,  sorucedata, ref targetdataLen);

            if (targetdataLen > 0)
            {
                byte[] ys = new byte[targetdataLen];
                Marshal.Copy(sorucedata, ys, 0, targetdataLen);
                string resultStr = Encoding.Default.GetString(ys);
                return resultStr;
            }
            return string.Empty;

        }

        //protected byte[] GenPayLoadData<T>(T entity)
        //{
        //    List<byte[]> dataContent = new List<byte[]>();
        //    Type type = entity.GetType();
        //    PropertyInfo[] propertyInfo = type.GetProperties();
        //    foreach (var VARIABLE in propertyInfo)
        //    {
        //        dataContent.Add(SetData());
        //    }
        //}

        protected byte[] SetData<T>(T paramData, int length) 
        {
            byte[] data = new byte[] { };

            if (paramData is string)
            {
                data = Encoding.Default.GetBytes(paramData as string);
            }

            if (paramData is int)
            {
                data = BitConverter.GetBytes(int.Parse(paramData.ToString()));
            }

            if (paramData is decimal)
            {
                data = BitConverter.GetBytes(float.Parse(paramData.ToString()));
            }

            if (paramData is DateTime && length == 11)
            {
                data = Encoding.Default.GetBytes(DateTime.Parse(paramData.ToString()).ToString("yyyy-MM-dd"));
            }

            if (paramData is DateTime && length == 20)
            {
                data = Encoding.Default.GetBytes(DateTime.Parse(paramData.ToString()).ToString("yyyy-MM-ddTHH:mm:ss"));
            }

            List<byte[]> al = new List<byte[]>();
            int diff = length - data.Length;
            al.Add(data);
            for (int i = 0; i < diff; i++)
            {
                al.Add(new byte[] { 0x00 });
            }
            MemoryStream ms = new MemoryStream();
            foreach (byte[] item in al)
            {
                ms.Write(item, 0, item.Length);
            }
            byte[] res = ms.ToArray();
            ms.Close();
            return res;
        }

        /// <summary>
        /// 格式化数据长度
        /// </summary>
        /// <param name="data"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        protected byte[] SetData(byte[] data, int length)
        {
            List<byte[]> al = new List<byte[]>();
            int diff = length - data.Length;
            al.Add(data);
            for (int i = 0; i < diff; i++)
            {
                al.Add(new byte[] { 0x00 });
            }
            MemoryStream ms = new MemoryStream();
            foreach (byte[] item in al)
            {
                ms.Write(item, 0, item.Length);
            }
            byte[] res = ms.ToArray();
            ms.Close();
            return res;
        }

        protected int Crc16(byte[] data)
        {
                    
            Crc16Util crcutil = new Crc16Util();
            return crcutil.CalcCrc16(data);
         
        }

        /** 
   * 将LittleEndian转换为BigEndian 
   *  
   * @param bytes 
   * @return 
   */
        public static byte[] LittleToBig(byte[] bytes)
        {
            if (bytes == null)
            {
                throw new Exception();
            }
            byte[] temp = new byte[bytes.Length];
            for (int i = bytes.Length - 1; i >= 0; i--)
            {
                temp[i] = bytes[bytes.Length - 1 - i];
            }
            return temp;
        }

        /** 
         * 将BigEndian转换为LittleEndian 
         *  
         * @param bytes 
         * @return 
         */
        public static byte[] BigToLittle(byte[] bytes)
        {
            return LittleToBig(bytes);
        }  
    }
}
